package com.ruoyi.controller;

import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.dto.GasExplosionUndergroundDto;
import com.ruoyi.dto.RiverHydraulicInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * 燃气在地下空间爆炸危害预警模型
 * 根据输入参数计算燃气泄漏爆炸的危害半径
 */
@Api(tags = "燃气在地下空间爆炸危害预警模型")
@RequestMapping("/gasExplosionWarningModel")
@RestController
public class GasExplosionWarningModelController {

    // 常量定义
    private static final double P0 = 101300.0; // 标准大气压，Pa
    private static final double R_GAS = 518.0; // 天然气气体常数，J/(kg·K)
    private static final double K = 1.29; // 天然气等熵指数
    private static final double M = 16.0; // 相对分子质量
    private static final double QF = 53044.0; // 天然气燃烧热，kJ/kg
    private static final double Q_TNT = 4520.0; // TNT爆热，kJ/kg
    private static final double ALPHA_TNT = 0.04; // 蒸气云的TNT当量系数

    // 输入参数类
    public static class InputParameters {
        public double pressure = 200000.0; // 泄漏管道压力，Pa
        public double temperature = 285.0; // 气体温度，K
        public String leakShape = "circle"; // 泄漏口形状
        public double leakDiameter = 0.01; // 泄漏口直径，m
        public double leakTime; // 泄漏时间，s

        public InputParameters(double leakTime) {
            this.leakTime = leakTime;
        }

        public InputParameters(double pressure, double temperature, String leakShape,
                               double leakDiameter, double leakTime) {
            this.pressure = pressure;
            this.temperature = temperature;
            this.leakShape = leakShape;
            this.leakDiameter = leakDiameter;
            this.leakTime = leakTime;
        }
    }

    // 计算结果类
    public static class CalculationResult {
        public double totalLeakageMass; // 总泄漏质量，kg
        public double tntEquivalent; // TNT当量，kg
        public double deathRadius; // 死亡半径，m
        public double seriousInjuryRadius; // 重伤半径，m
        public double minorInjuryRadius; // 轻伤半径，m

        @Override
        public String toString() {
            return String.format(
                    "计算结果:\n" +
                            "总泄漏质量: %.6f kg\n" +
                            "TNT当量: %.6f g\n" +
                            "死亡半径: %.2f m\n" +
                            "重伤半径: %.2f m\n" +
                            "轻伤半径: %.2f m",
                    totalLeakageMass, tntEquivalent,
                    deathRadius, seriousInjuryRadius, minorInjuryRadius
            );
        }
    }

    // 获取泄漏口形状对应的流量系数
    private static double getFlowCoefficient(String leakShape) {
        Map<String, Double> shapeCoefficients = new HashMap<>();
        shapeCoefficients.put("circle", 1.00);
        shapeCoefficients.put("triangle", 0.95);
        shapeCoefficients.put("rectangle", 0.90);

        return shapeCoefficients.getOrDefault(leakShape, 1.00);
    }

    // 计算总泄漏质量
    public static double calculateTotalLeakageMass(InputParameters params) {
        double alpha = getFlowCoefficient(params.leakShape);
        double d = params.leakDiameter;
        double P = params.pressure;
        double T = params.temperature;
        double t = params.leakTime;

        // 根据图片中的精确公式：
        // Qm = (απd²/4) * (P/√(RT)) * √[κM(2/(κ+1))^((κ+1)/(κ-1))] * t

        // 计算第一部分：(απd²/4)
        double areaFactor = (alpha * Math.PI * d * d) / 4.0;

        // 计算第二部分：(P/√(RT))
        double pressureFactor = P / Math.sqrt(R_GAS * T);

        // 计算第三部分：√[κM(2/(κ+1))^((κ+1)/(κ-1))]
        // 先计算指数部分：(2/(κ+1))^((κ+1)/(κ-1))
        double exponentBase = 2.0 / (K + 1.0);
        double exponent = (K + 1.0) / (K - 1.0);
        double exponentResult = Math.pow(exponentBase, exponent);

        // 计算根号内的内容：κM * (2/(κ+1))^((κ+1)/(κ-1))
        double sqrtContent = K * M * exponentResult;

        // 计算平方根
        double sqrtFactor = Math.sqrt(sqrtContent);

        // 总泄漏质量 = 面积因子 * 压力因子 * 平方根因子 * 时间
        return areaFactor * pressureFactor * sqrtFactor * t;
    }

    // 计算TNT当量
    public static double calculateTNTEquivalent(double totalLeakageMass) {
        // WTNT = (Qm * Qf * α) / Q_TNT
        return 1000*(totalLeakageMass * QF * ALPHA_TNT) / Q_TNT;
    }

    // 计算死亡半径
    public static double calculateDeathRadius(double tntEquivalent) {
        // R1 = 13.6 * (W_TNT / 1000)^(1/3)
        return 13.6 * Math.pow(tntEquivalent / 1000.0, 1.0/3.0);
    }

    // 计算重伤半径
    public static double calculateSeriousInjuryRadius(double tntEquivalent) {
        // R2 = 1.099 * (W_TNT * 4520 / P0)^(1/8)
        return 1.099 * Math.pow((tntEquivalent * 1000 * Q_TNT) / P0, 1.0/3.0);
    }

    // 计算轻伤半径
    public static double calculateMinorInjuryRadius(double tntEquivalent) {
        // R3 = 1.96 * (W_TNT * 4520 / P0)^(1/8)
        return 1.96 * Math.pow((tntEquivalent * 1000 * Q_TNT) / P0, 1.0/3.0);
    }

    // 执行完整计算
    public static CalculationResult calculate(InputParameters params) {
        CalculationResult result = new CalculationResult();

        // 1. 计算总泄漏质量
        result.totalLeakageMass = calculateTotalLeakageMass(params);

        // 2. 计算TNT当量
        result.tntEquivalent = calculateTNTEquivalent(result.totalLeakageMass);

        // 3. 计算危害半径
        result.deathRadius = calculateDeathRadius(result.tntEquivalent);
        result.seriousInjuryRadius = calculateSeriousInjuryRadius(result.tntEquivalent);
        result.minorInjuryRadius = calculateMinorInjuryRadius(result.tntEquivalent);

        return result;
    }

    @ApiOperation("燃气在地下空间爆炸危害预警模型")
    @PostMapping("/undergroundSpace")
    public AjaxResult undergroundSpace(@RequestBody GasExplosionUndergroundDto gasExplosionUndergroundDto) {
        AjaxResult ajaxResult = new AjaxResult();
        Map map = new HashMap();
        map.put("number" , gasExplosionUndergroundDto.getNumber());
        InputParameters params = new InputParameters(gasExplosionUndergroundDto.getPressure(),
                gasExplosionUndergroundDto.getTemperature(), gasExplosionUndergroundDto.getLeakShape(),
                gasExplosionUndergroundDto.getLeakDiameter(), gasExplosionUndergroundDto.getLeakTime());

        CalculationResult result = calculate(params);

        map.put("totalLeakageMass" , result.totalLeakageMass);
        map.put("tntEquivalent" , result.tntEquivalent);
        map.put("deathRadius" , result.deathRadius);
        map.put("seriousInjuryRadius" , result.seriousInjuryRadius);
        map.put("minorInjuryRadius" , result.minorInjuryRadius);


        map.put("input" , gasExplosionUndergroundDto);

        return ajaxResult.success(map);
    }
        // 示例使用
    public static void main(String[] args) {
        // 使用默认参数，泄漏时间60秒
        InputParameters params = new InputParameters(200000, 285, "circle", 0.01, 60);

        CalculationResult result = calculate(params);
        System.out.println("燃气爆炸危害预警模型计算结果（最终修正版）");
        System.out.println("输入参数:");
        System.out.printf("管道压力: %.0f Pa\n", params.pressure);
        System.out.printf("气体温度: %.1f K\n", params.temperature);
        System.out.printf("泄漏口形状: %s\n", params.leakShape);
        System.out.printf("泄漏口直径: %.3f m\n", params.leakDiameter);
        System.out.printf("泄漏时间: %.1f s\n", params.leakTime);
        System.out.println("\n" + result.toString());

        // 测试不同参数
        System.out.println("\n=== 测试不同泄漏时间 ===");
        InputParameters params2 = new InputParameters(200000, 285, "circle", 0.01, 120);
        CalculationResult result2 = calculate(params2);
        System.out.println(result2.toString());

        // 测试不同泄漏口形状
        System.out.println("\n=== 测试不同泄漏口形状 ===");
        InputParameters params3 = new InputParameters(200000, 285, "triangle", 0.01, 60);
        CalculationResult result3 = calculate(params3);
        System.out.println(result3.toString());

        // 测试不同压力
        System.out.println("\n=== 测试不同压力 ===");
        InputParameters params4 = new InputParameters(500000, 285, "circle", 0.01, 60);
        CalculationResult result4 = calculate(params4);
        System.out.println(result4.toString());
    }
}
